package com.seng.resourcetycoon.util;

import com.seng.resourcetycoon.core.enums.ResourceType;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.EnumSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;

public class TowerAttributeGenerator implements AttributeGenerator {

    private static final Random random = new Random();
    private static final int MAX_CAPACITY = 10;

    /**
     * Generate a randomized resource amount based on the resource type and a predefined range
     *
     * @return
     */
    @Override
    public  int generateRandomCapacity(ResourceType resourceType) {
        // Define a min and max resource amount range for each resource type

        switch (resourceType) {
            case WATER:
                // For water towers, generate a capacity between ¼ and ¾ of the maximum capacity
                int waterMinCapacity = MAX_CAPACITY / 4;
                int waterMaxCapacity = MAX_CAPACITY * 3 / 4;
                return random.nextInt(waterMaxCapacity - waterMinCapacity + 1) + waterMinCapacity;

            case FOOD:
                // For food towers, generate a capacity between ½ and ⅞ of the maximum capacity
                int foodMinCapacity = MAX_CAPACITY / 2;
                int foodMaxCapacity = MAX_CAPACITY * 7 / 8;
                return random.nextInt(foodMaxCapacity - foodMinCapacity + 1) + foodMinCapacity;

            case MATERIALS:
                // For building materials towers, generate a capacity between ⅜ and the maximum capacity
                int buildingMaterialsMinCapacity = MAX_CAPACITY * 3 / 8;
                return random.nextInt(MAX_CAPACITY - buildingMaterialsMinCapacity + 1) + buildingMaterialsMinCapacity;

            // Handle other resource types if needed
        }

        throw new RuntimeException("not support " + resourceType.getDescription());
    }

    /**
     * Generate a randomized reload time within a predefined range
     *
     * @return
     */
    @Override
    public  double getRandomizedReloadTimeMillis() {
        // Use ThreadLocalRandom for thread safety in a multithreaded environment.
        Random random = ThreadLocalRandom.current();

        // Generate a random value within the specified range (2.0 to 4.9).
        double number = random.nextDouble(3) + 2;

        // Improved precision for rounding to the nearest tenth using BigDecimal.
        BigDecimal bdNumber = new BigDecimal(number * 10);
        bdNumber = bdNumber.setScale(1, RoundingMode.HALF_UP).divide(BigDecimal.valueOf(10),10, RoundingMode.HALF_DOWN);

        return bdNumber.doubleValue();
    }

    @Override
    public  ResourceType generateRandomResourceType() {
        Set<ResourceType> allResourceTypes = EnumSet.allOf(ResourceType.class);
        return getRandomEnum(random, allResourceTypes);
    }

    @Override
    public  ResourceType generateUniqueResourceType(Set<ResourceType> generatedResourceTypes) {
        if(generatedResourceTypes == null){
            return null;
        }
        ResourceType resourceType;
        do {
            resourceType = generateRandomResourceType();
        } while (generatedResourceTypes.contains(resourceType)); // 循环直到找到一个未生成过的资源类型
        generatedResourceTypes.add(resourceType); // 记录已生成的资源类型
        return resourceType;
    }

    private  <E extends Enum<E>> E getRandomEnum(Random random, Set<E> enumValues) {
        int randomIndex = random.nextInt(enumValues.size());
        return enumValues.stream()
                .skip(randomIndex)
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("Enum set should never be empty"));
    }


    /**
     * Default buy price calculation based on the resource type
     *
     * @param resourceType
     * @return
     */
    @Override
    public BigDecimal getDefaultBuyPrice(ResourceType resourceType) {
        switch (resourceType) {
            case WATER:
                return BigDecimal.valueOf(50.0);
            case FOOD:
                return BigDecimal.valueOf(90.0);
            case MATERIALS:
                return BigDecimal.valueOf(120.0);
            // Handle other resource types or provide a default value
        }
        throw new RuntimeException("not find price for " + resourceType.getDescription());
    }
}
